﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows;
using System.Windows.Browser;
using GiveAQuiz.Client.Data.DataServices;
using GiveAQuiz.Common;
using GiveAQuiz.Common.Mvvm;
using GiveAQuiz.QuizManager.Interfaces;


namespace GiveAQuiz.QuizManager.ViewModel
{
  [Export("QuizViewModel")]
  public class QuizViewModel : ViewModelBase
  {
    QuizDefinition _quizDefinition = null;
    IQuizModel _theModel = null;
    bool _isEditingInfo = false;
    ViewCommand _saveCommand = null;
    ViewCommand _cancelCommand = null;
    ViewCommand _editInfoCommand = null;
    ViewCommand<IQuestionType> _addQuestionCommand = null;
    ViewCommand<IQuestionType> _moveUpQuestionCommand = null;
    ViewCommand<IQuestionType> _moveDownQuestionCommand = null;
    ViewCommand<IQuestionType> _deleteQuestionCommand = null;
    List<IQuestionType> _toolbarItems = null;
    ObservableCollection<IQuestionType> _questions = new ObservableCollection<IQuestionType>();

    [ImportingConstructor]
    public QuizViewModel(IQuizModel model)
    {
      // Set the Initial members
      _theModel = model;
      _editInfoCommand = new ViewCommand(() => AppMessages.EditDetailsMessage.Send());
      _addQuestionCommand = new ViewCommand<IQuestionType>(type => AddQuestion(type));
      _deleteQuestionCommand = new ViewCommand<IQuestionType>(type => DeleteQuestion(type));
      _moveUpQuestionCommand =
        new ViewCommand<IQuestionType>(type => MoveQuestion(type, -1),
                                       type => Questions.IndexOf(type) > 0);
      _moveDownQuestionCommand =
        new ViewCommand<IQuestionType>(type => MoveQuestion(type, 1),
                                       type => Questions.IndexOf(type) < Questions.Count - 1);
      _saveCommand = new ViewCommand(() => SaveQuizAsync());
      _cancelCommand = new ViewCommand(() => Cancel());

      // When the collection changes, renumber the questions
      Questions.CollectionChanged += (s, e) => RenumberQuestions();

      // Respond to the Busy Message to show actions happen
      AppMessages.IsBusyMessage.Register(this, b => IsBusy = b);

      // Load the Data Asynchronously 
      LoadQuizDefinitionAsync();
    }

    void AddQuestion(IQuestionType type)
    {
      if (type != null)
      {
        var def = _theModel.CreateQuestionDefinition(type);
        def.QuizDefinitionKey = QuizDefinition.Id;
        var copy = QuestionHelper.Copy(type);
        copy.Definition = def;
        Questions.Add(copy);
      }
    }

    void DeleteQuestion(IQuestionType type)
    {
      _theModel.DeleteQuestionDefinition(type.Definition);
      Questions.Remove(type);
    }

    void MoveQuestion(IQuestionType type, int direction)
    {
      int currentPosition = Questions.IndexOf(type);
      Questions.Remove(type);
      Questions.Insert(currentPosition + direction, type);
    }

    void RenumberQuestions()
    {
      // Change the numbers
      var i = 1;
      foreach (var q in Questions) q.Definition.SortOrder = i++;

      // Force the recalcuation of the commands
      MoveDownQuestionCommand.RaiseCanExecuteChanged();
      MoveUpQuestionCommand.RaiseCanExecuteChanged();
    }

    public ViewCommand SaveCommand
    {
      get { return _saveCommand; }
    }

    public ViewCommand CancelCommand
    {
      get { return _cancelCommand; }
    }

    public ViewCommand EditInfoCommand
    {
      get { return _editInfoCommand; }
    }

    public ViewCommand<IQuestionType> AddQuestionCommand
    {
      get { return _addQuestionCommand; }
    }

    public ViewCommand<IQuestionType> DeleteQuestionCommand
    {
      get { return _deleteQuestionCommand; }
    }

    public ViewCommand<IQuestionType> MoveUpQuestionCommand
    {
      get { return _moveUpQuestionCommand; }
    }

    public ViewCommand<IQuestionType> MoveDownQuestionCommand
    {
      get { return _moveDownQuestionCommand; }
    }

    public void Cancel()
    {
      HtmlPage.Window.Navigate(new Uri("/Quiz", UriKind.Relative));
    }

    public void SaveQuizAsync()
    {
      if (!_questions.All(q => q.ValidateQuestion()))
      {
        ErrorMessage = "Cannot save until the questions are all valid.  Please correct any errors.";
        return;
      }

      ErrorMessage = "";

      _theModel.SaveAsync(ex => 
        {
          if (ex != null)
          {
            ErrorMessage = ex.Message;
#if DEBUG
            MessageBox.Show(ex.ToString());
#endif
          }
          else
          {
            HtmlPage.Window.Navigate(new Uri("/Quiz", UriKind.Relative), "_self");
          }
        });
    }

    public void LoadQuizDefinitionAsync()
    {
      ErrorMessage = "";

      if (App.CurrentApp.IsNewQuiz)
      {
        QuizDefinition = new QuizDefinition() 
          { 
            QuizName = "(Enter Quiz Name)", 
            Description = ""
          };
        _theModel.AddQuizToModel(QuizDefinition);
      }
      else
      {
        _theModel.GetQuizDefinitionAsync(App.CurrentApp.QuizDefinitionID, (quizDef, exception) =>
          {
            if (exception != null)
            {
              ErrorMessage = exception.Message;
            }
            else
            {
              QuizDefinition = quizDef;
              foreach (var q in QuizDefinition.QuestionDefinitions)
              {
                var qType = QuestionHelper.CreateQuestionType(q.QuestionTypeName);
                if (qType != null)
                {
                  qType.Definition = q;
                  qType.QuestionData = q.QuestionData;
                  Questions.Add(qType);
                }
              }
            }
          });
      }
    }

    public bool IsEditingInfo
    {
      get
      {
        return _isEditingInfo;
      }
      private set
      {
        if (_isEditingInfo != value)
        {
          _isEditingInfo = value;
          RaisePropertyChanged("IsEditingInfo");
        }
      }
    }

    public QuizDefinition QuizDefinition
    {
      get
      {
        return _quizDefinition;
      }
      private set
      {
        if (_quizDefinition != value)
        {
          _quizDefinition = value;
          RaisePropertyChanged("QuizDefinition");
        }

      }
    }

    public ObservableCollection<IQuestionType> Questions
    {
      get { return _questions; }
      private set
      {
        if (_questions != value)
        {
          _questions = value;
          RaisePropertyChanged("Questions");
        }

      }
    }



    [ImportMany(typeof(IQuestionType))]
    public List<IQuestionType> ToolbarItems
    {
      get
      {
        return _toolbarItems;
      }
      set
      {
        if (_toolbarItems != value)
        {
          _toolbarItems = value;
          RaisePropertyChanged("ToolbarItems");
        }
      }
    }
  }
}
